package com.xiaoh.dormitoryrepairreportbackend.controller;

import cn.hutool.json.JSONUtil;
import com.xiaoh.dormitoryrepairreportbackend.annotation.RequireRole;
import com.xiaoh.dormitoryrepairreportbackend.common.BaseResponse;
import com.xiaoh.dormitoryrepairreportbackend.common.ErrorCode;
import com.xiaoh.dormitoryrepairreportbackend.constant.UserConstant;
import com.xiaoh.dormitoryrepairreportbackend.exception.BusinessException;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.ai.AiRecommendationResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.common.PageResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.common.UpdateRequest;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.workorder.*;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.GeneralUser;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.RepairCategory;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.WorkOrder;
import com.xiaoh.dormitoryrepairreportbackend.service.AiWorkOrderAssignmentService;
import com.xiaoh.dormitoryrepairreportbackend.service.GeneralUserService;
import com.xiaoh.dormitoryrepairreportbackend.service.RepairCategoryService;
import com.xiaoh.dormitoryrepairreportbackend.service.WorkOrderService;
import com.xiaoh.dormitoryrepairreportbackend.utils.UserHolder;
import com.xiaoh.dormitoryrepairreportbackend.utils.WorkOrderConverter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * 工单接口
 */
@RestController
@RequestMapping("/workorder")
@Slf4j
@Tag(name = "工单管理", description = "工单相关接口")
public class WorkOrderController {

    @Lazy
    @Resource
    private WorkOrderService workOrderService;

    @Lazy
    @Resource
    private AiWorkOrderAssignmentService aiWorkOrderAssignmentService;

    @Resource
    private GeneralUserService generalUserService;

    @Resource
    private RepairCategoryService repairCategoryService;

    /**
     * 创建工单
     */
    @PostMapping("/add")
    @Operation(summary = "创建工单", description = "创建工单接口")
    @RequireRole({UserConstant.UserType.STUDENT, UserConstant.UserType.ADMIN})
    public BaseResponse<Long> addWorkOrder(@Valid @RequestBody WorkOrderAddRequest workOrderAddRequest, HttpServletRequest request) {
        if (workOrderAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        WorkOrder workOrder = new WorkOrder();
        BeanUtils.copyProperties(workOrderAddRequest, workOrder);

        // 设置图片URL
        if (workOrderAddRequest.getImagesUrl() != null && !workOrderAddRequest.getImagesUrl().isEmpty()) {
            workOrder.setImagesUrl(JSONUtil.toJsonStr(workOrderAddRequest.getImagesUrl()));
        }

        // 获取当前用户
        workOrder.setReporterId(UserHolder.getCurrentUserId());

        // 使用AI自动分配
        Long workOrderId = workOrderService.createWorkOrderWithAiAssignment(workOrder);
        return BaseResponse.success(workOrderId);
    }

    /**
     * 删除工单
     */
    @PostMapping("/delete")
    @Operation(summary = "删除工单", description = "删除工单接口")
    @RequireRole(value = {UserConstant.UserType.STUDENT, UserConstant.UserType.ADMIN}, allowSelf = true)
    public BaseResponse<Boolean> deleteWorkOrder(@Valid @RequestBody UpdateRequest updateRequest, HttpServletRequest request) {
        WorkOrder workOrder = getWorkOrder(updateRequest);
        boolean b = workOrderService.removeById(workOrder.getId());
        return BaseResponse.success(b);
    }

    /**
     * 更新工单
     */
    @PostMapping("/update")
    @Operation(summary = "更新工单", description = "更新工单接口")
    public BaseResponse<Boolean> updateWorkOrder(@Valid @RequestBody WorkOrderUpdateRequest workOrderUpdateRequest, HttpServletRequest request) {
        if (workOrderUpdateRequest == null || workOrderUpdateRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        WorkOrder workOrder = new WorkOrder();
        BeanUtils.copyProperties(workOrderUpdateRequest, workOrder);

        // 设置图片URL
        if (workOrderUpdateRequest.getImagesUrl() != null && !workOrderUpdateRequest.getImagesUrl().isEmpty()) {
            workOrder.setImagesUrl(JSONUtil.toJsonStr(workOrderUpdateRequest.getImagesUrl()));
        }

        long id = workOrderUpdateRequest.getId();
        // 校验数据是否存在
        WorkOrder oldWorkOrder = workOrderService.getById(id);
        if (oldWorkOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }

        // 检查权限：只有报修人、处理人或管理员可以更新工单
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        GeneralUser currentUser = (GeneralUser) userObj;
        if (!oldWorkOrder.getReporterId().equals(currentUser.getId()) &&
                !currentUser.getId().equals(oldWorkOrder.getHandlerId()) &&
                (currentUser.getUserType() == null || currentUser.getUserType() != UserConstant.UserType.ADMIN)) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
        }
        workOrderService.updateWorkOrderStatus(workOrder.getId(), workOrder.getStatus(), UserHolder.getCurrentUserId());
        boolean result = workOrderService.updateById(workOrder);
        return BaseResponse.success(result);
    }

    /**
     * 根据 id 获取工单
     */
    @PostMapping("/get")
    @Operation(summary = "根据id获取工单", description = "根据id获取工单")
    public BaseResponse<WorkOrderResponse> getWorkOrderById(@Valid @RequestBody UpdateRequest updateRequest) {
        WorkOrder workOrder = getWorkOrder(updateRequest);
        WorkOrderResponse workOrderResponse = getWorkOrderResponse(workOrder);
        return BaseResponse.success(workOrderResponse);
    }

    private WorkOrderResponse getWorkOrderResponse(WorkOrder workOrder) {
        // 转换 查出报修人和维修人 维修类别
        GeneralUser reporter = generalUserService.getById(workOrder.getReporterId());
        GeneralUser handler = generalUserService.getById(workOrder.getHandlerId());
        RepairCategory category = repairCategoryService.getById(workOrder.getCategoryId());
        Map<Long, GeneralUser> userMap = new HashMap<>();
        if (reporter != null) {
            userMap.put(reporter.getId(), reporter);
        }
        if (handler != null) {
            userMap.put(handler.getId(), handler);
        }
        Map<Integer, RepairCategory> categoryMap = new HashMap<>();
        if (category != null) {
            categoryMap.put(category.getId(), category);
        }
        return WorkOrderConverter.toWorkOrderResponse(workOrder, userMap, categoryMap);
    }

    private WorkOrder getWorkOrder(UpdateRequest updateRequest) {
        if (updateRequest == null || updateRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long id = updateRequest.getId();
        WorkOrder workOrder = workOrderService.getById(id);
        if (workOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        return workOrder;
    }

    /**
     * 分页获取工单列表
     * 使用游标分页保持性能，同时返回完整分页信息
     */
    @PostMapping("/list/page")
    @Operation(summary = "分页获取工单列表", description = "支持通过账号、类别名称等查询，返回脱敏的用户信息和完整分页信息（总记录数、总页数等）")
    public BaseResponse<PageResponse<WorkOrderResponse>> listWorkOrderByPage(@RequestBody WorkOrderQueryRequest workOrderQueryRequest) {
        if (workOrderQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        PageResponse<WorkOrderResponse> pageResponse = workOrderService.listWorkOrderPageWithConditions(workOrderQueryRequest);
        return BaseResponse.success(pageResponse);
    }

    /**
     * 分配工单
     */
    @PostMapping("/assign")
    @Operation(summary = "分配工单", description = "分配工单给维修工")
    @RequireRole(UserConstant.UserType.ADMIN)
    public BaseResponse<Boolean> assignWorkOrder(@Valid @RequestBody WorkOrderAssignRequest assignRequest) {
        if (assignRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long workOrderId = assignRequest.getWorkOrderId();
        Long handlerId = assignRequest.getHandlerId();

        boolean result = workOrderService.assignWorkOrder(workOrderId, handlerId);
        return BaseResponse.success(result);
    }

    /**
     * AI推荐维修人员
     */
    @PostMapping("/recommend-maintenance")
    @Operation(summary = "AI推荐维修人员", description = "根据工单信息AI推荐合适的维修人员，使用与添加工单时自动分配维修工一致的AI逻辑")
    @RequireRole(UserConstant.UserType.ADMIN)
    public BaseResponse<AiRecommendationResponse> recommendMaintenanceWorkers(@Valid @RequestBody WorkOrderRecommendRequest recommendRequest) {
        if (recommendRequest == null || recommendRequest.getWorkOrderId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Integer count = recommendRequest.getCount();
        if (count == null || count <= 0) {
            count = 5; // 默认推荐5个
        }
        if (count > 10) {
            count = 10; // 最多推荐10个
        }

        AiRecommendationResponse recommendations =
                aiWorkOrderAssignmentService.recommendMaintenanceWorkersWithAiResult(
                        recommendRequest.getWorkOrderId(), count);
        return BaseResponse.success(recommendations);
    }

    /**
     * 评价工单
     */
    @PostMapping("/review")
    @Operation(summary = "评价工单", description = "对已完成的工单进行评价")
    @RequireRole({UserConstant.UserType.STUDENT, UserConstant.UserType.ADMIN})
    public BaseResponse<Boolean> reviewWorkOrder(@Valid @RequestBody WorkOrderReviewRequest reviewRequest) {
        if (reviewRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long workOrderId = reviewRequest.getWorkOrderId();
        Integer rating = reviewRequest.getRating();
        String reviewComment = reviewRequest.getReviewComment();

        boolean result = workOrderService.reviewWorkOrder(workOrderId, rating, reviewComment, UserHolder.getCurrentUserId());
        return BaseResponse.success(result);
    }

    /**
     * 获取工单统计信息
     */
    @PostMapping("/stats")
    @Operation(summary = "获取工单统计信息", description = "获取工单各状态的统计数据")
    @RequireRole(UserConstant.UserType.ADMIN)
    public BaseResponse<WorkOrderStatsResponse> getWorkOrderStats() {
        WorkOrderStatsResponse stats = workOrderService.getWorkOrderStats();
        return BaseResponse.success(stats);
    }

    /**
     * 更新工单状态
     */
    @PostMapping("/update-status")
    @Operation(summary = "更新工单状态", description = "更新工单状态，遵循状态转换规则")
    @RequireRole({UserConstant.UserType.MAINTENANCE, UserConstant.UserType.ADMIN})
    public BaseResponse<Boolean> updateWorkOrderStatus(@Valid @RequestBody WorkOrderStatusUpdateRequest statusUpdateRequest) {
        if (statusUpdateRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        Long workOrderId = statusUpdateRequest.getWorkOrderId();
        Integer status = statusUpdateRequest.getStatus();
        Long operatorId = UserHolder.getCurrentUserId();

        // 验证工单是否存在
        WorkOrder workOrder = workOrderService.getById(workOrderId);
        if (workOrder == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "工单不存在");
        }

        // 检查权限：只有处理人或管理员可以更新状态
        GeneralUser currentUser = UserHolder.getCurrentUser();
        if (!currentUser.getId().equals(workOrder.getHandlerId()) &&
            currentUser.getUserType() != UserConstant.UserType.ADMIN) {
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "只有工单处理人或管理员可以更新状态");
        }

        boolean result = workOrderService.updateWorkOrderStatus(workOrderId, status, operatorId);
        return BaseResponse.success(result);
    }
}
